# -*- coding: utf-8 -*-
'''
 Source file
 File name: tag.py
 Creation date: 29-12-2011
 Author: itey

'''

from svi.command.basecmd import *
from svi.core.svnutils import is_svn
import getopt
import sys
import re
import pysvn

class command(BaseCmd):
    ''' Tag creation management '''

    def __init__(self, param, client, conf):
        ''' param: list of arguement
            client: svn client object
            conf: Config object
        '''
        self._forcing = False
        self._rev = None 
        # Call base class initialisation
        super(command, self).__init__(param, client, conf)

    def help(self):
        self._msg.banner()
        self._msg.help(u'"tag" command inline help')
        self._msg.help(u'''Syntaxe: svi tag [-f] [-r] [-r <revision>] <file>|<directory> <file>|<directory> ... <tag name>
                Create a new tag <tag name> and copy <file> or <directory> and its contents into it. The tag is located in tag directory found in configuration file.
                -f:             Forcing the tag if <file> or <directory> already exist
                -r <revision>:  Revision of <file> or directory> to tag
                -v:             Verbose for debug
                <file> or <directory> can be path in local snapshot view, or URL from server side, but they are copied from server side
                <tag name> is directly created on server side''')
 

    def run(self):
        ''' Execute command, and raise error if any
        '''

        # Parse argument
        try:
            opts, arg_list = getopt.getopt(self._param, 'r:f')
        except getopt.GetoptError, err:
            # print error message
            self._msg.error(err)
            self.help()
            sys.exit(2)

        # They are options
        if len(opts) != 0:
            for index in range(len(opts)):
                o, a = opts[index]
                # option forcing tag
                if o == "-f":
                    self._forcing = True
                #option revision tag
                elif o == "-r":
                    if a.isdigit() is False:
                        self.help()
                        raise CommandLineError(u'Option "-r" must be followed by a SVN revision number ("%s" is not a number)' % a)
                    # Store revision
                    self._rev =  int(a)                  
        
        # 'arg_list' must not be empty, and must contains at least to value
        if len(arg_list) < 2:
            self.help()
            raise CommandLineError(u'Missing argument')
        # Last argument is the tag name
        tag_name = arg_list[-1]
        file_list = arg_list[0:-1]
        
        if self.tag_name_is_valid(tag_name) is True:
            self._tag_name = tag_name
        else:
            raise ParameterError(u'%s is not a Tag name valid' % tag_name)

        # Create tab of all url files to tag 
        all_url=[]

        # check all files exist and save url
        for index in range(len(file_list)):
            # Revision is given
            if self._rev is not None:
                # Get SVN module from 'file_list' 
                try:
                    svn_module = self._client.info2(file_list[index],pysvn.Revision(pysvn.opt_revision_kind.number, self._rev))
                except:
                    # Parameter is not a SVN repository
                    raise ParameterError(u'%s is not a SVN location at revision %d' % (file_list[index],self._rev))
            # Revision is not given
            else:
                # Get SVN module from 'file_list' 
                try:
                    svn_module = self._client.info2(file_list[index])
                except:
                    # Parameter is not a SVN repository
                    raise ParameterError(u'%s is not a SVN location' % file_list[index])
                
            # add the url of file
            all_url.append(svn_module[0][1]['URL'])
        
        #Get the name of server
        self._server_name = self._client.root_url_from_path(all_url[0])
        #Get the directory of main data in server
        self._main = self._conf.get("core","main")
        #Get the directory of tag data in server
        self._tag = self._conf.get("core","tags")
        #Log message for the tag
        self._logMessage = "Create tag " + self._tag_name

        #For all url to tag : Create Directory and tag file
        for index in range(len(all_url)):
            #Retrieve the directories to create
            url_temp = re.sub((self._main + "/"),"",all_url[index])
            url_temp = re.sub(self._server_name,"",url_temp)
            #Verification if there are directories to create
            if re.search('/',url_temp) is not None:
                #Check and create tree in tag if don't exist
                for index2 in range(url_temp.count('/')+1):
                    occur = '((\w+)/){'+str(index2)+'}' 
                    create_dir = re.match(occur,url_temp)
                    url_creat_dir = self._server_name + self._tag + '/' + self._tag_name + '/' + create_dir.group(0)
                    self.createDir(url_creat_dir)
            else:
                #If there isn't directory to create then create the directory of tag
                url_creat_dir = self._server_name + self._tag + '/' + self._tag_name 
                self.createDir(url_creat_dir)
            #Tag the file 
            self.tag(all_url[index])


    def createDir(self,url_create_dir):
        ''' url_create_dir: Url of directory to create
        '''
        #The directory don't exist then create the directory in tag
        if is_svn(url_create_dir) is False:
            self._client.mkdir(url_create_dir,self._logMessage)



    def tag(self,url_src):
        ''' url_src: Url of file or directory to tag
        '''
        #Create the url of the tag
        url_name_tag = re.sub(self._main,self._tag + '/' + self._tag_name,url_src)
        #Preparation of the log Message
        self._client.callback_get_log_message = lambda: (True, self._logMessage) 
               
        # Revision is given
        if self._rev is not None :
            try:
                #Tag the file or directory at the revision given in parameter
                self._client.copy(url_src,url_name_tag,pysvn.Revision(pysvn.opt_revision_kind.number,self._rev))
            except:
                #The file or directory to tag exist 
                self.retag(url_src,url_name_tag)
        # Revision is not given
        else:
            try:
                #Tag the file or directory at the head revision
                self._client.copy(url_src,url_name_tag)
            except:
                #The file or directory to tag exist 
                self.retag(url_src,url_name_tag)

    def retag(self,url_src,url_dst):               
        ''' url_src: Url of file or directory to tag
            url_dst: Url of tag
        '''
        #The parameter of forcing tag is set
        if self._forcing is True:
            #Preparation of the log Message of the remove file or directory in tag
            self._client.callback_get_log_message = lambda: (True, "Delete the file/directory "+ url_dst + ".") 
            #Remove the file or the directory in tag
            self._client.remove(url_dst,True) 
            #Preparation of the log Message for the tag 
            self._client.callback_get_log_message = lambda: (True, self._logMessage) 
            # Revision is given
            if self._rev is not None :
                #Tag the file or directory at the revision given in parameter
                self._client.copy(url_src,url_dst,pysvn.Revision(pysvn.opt_revision_kind.number,self._rev))
            # Revision is not given
            else:
                #Tag the file or directory at the head revision
                self._client.copy(url_src,url_dst)
        else:
            # The tag already exist and the forcing option is not set
            raise ParameterError(u'%s already exist in Tag %s' % (url_src, self._tag_name))

    def tag_name_is_valid(self,tag_name):
        ''' tag_name: Name of tag
        '''
        # Check if they is a character different from alphanumeric or _
        if re.search('\W',tag_name) is not None:
            # The tag name contain character different from alphanumeric or _ then tag name is not valid
            return False 
        else: 
            return True

                        
